const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
const cheerio = require('cheerio');

// 使用stealth插件避免被检测
puppeteer.use(StealthPlugin());

class TikTokScraperAdvanced {
  constructor() {
    this.browser = null;
    this.page = null;
  }

  /**
   * 等待指定时间（替代waitForTimeout）
   */
  async wait(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * 初始化浏览器
   */
  async initBrowser() {
    if (!this.browser) {
      // macOS特定配置
      const launchOptions = {
        headless: 'new',
        timeout: 60000, // 增加启动超时时间
        args: [
          '--no-sandbox',
          '--disable-setuid-sandbox',
          '--disable-dev-shm-usage',
          '--disable-accelerated-2d-canvas',
          '--no-first-run',
          '--no-zygote',
          '--disable-gpu',
          '--disable-web-security',
          '--disable-features=VizDisplayCompositor',
          '--window-size=375,812', // 移动端分辨率 (iPhone 13 Pro)
          '--disable-background-timer-throttling',
          '--disable-backgrounding-occluded-windows',
          '--disable-renderer-backgrounding',
          // 禁用媒体权限相关
          '--use-fake-ui-for-media-stream', // 使用假的UI来处理媒体流权限
          '--use-fake-device-for-media-stream', // 使用假设备
          '--disable-user-media-security=true', // 禁用用户媒体安全检查
          '--allow-running-insecure-content', // 允许不安全内容
          '--disable-web-security', // 禁用web安全
          '--disable-features=VizDisplayCompositor,AudioServiceOutOfProcess', // 禁用音频进程
          '--autoplay-policy=no-user-gesture-required', // 自动播放策略
          '--disable-background-timer-throttling',
          '--disable-ipc-flooding-protection'
        ],
        defaultViewport: {
          width: 375,
          height: 812,
          isMobile: true,
          hasTouch: true,
          deviceScaleFactor: 3
        }
      };

      // 在macOS上尝试使用系统Chrome
      if (process.platform === 'darwin') {
        const possiblePaths = [
          '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
          '/Applications/Chromium.app/Contents/MacOS/Chromium'
        ];

        for (const path of possiblePaths) {
          try {
            const fs = require('fs');
            if (fs.existsSync(path)) {
              launchOptions.executablePath = path;
              break;
            }
          } catch (e) {
            // 继续尝试下一个路径
          }
        }
      }

      this.browser = await puppeteer.launch(launchOptions);
    }
    return this.browser;
  }

  /**
   * 创建新页面
   */
  async createPage() {
    const browser = await this.initBrowser();
    const page = await browser.newPage();

    // 设置移动端用户代理
    await page.setUserAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 17_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Mobile/15E148 Safari/604.1');

    // 设置移动端视窗大小
    await page.setViewport({
      width: 375,
      height: 812,
      isMobile: true,
      hasTouch: true,
      deviceScaleFactor: 3
    });

    // 设置移动端的请求头
    await page.setExtraHTTPHeaders({
      'Accept-Language': 'en-US,en;q=0.9',
      'Accept-Encoding': 'gzip, deflate, br',
      'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
      'Connection': 'keep-alive',
      'Upgrade-Insecure-Requests': '1',
      'Sec-CH-UA-Mobile': '?1',
      'Sec-CH-UA-Platform': '"iOS"'
    });

    // 禁用媒体权限请求（摄像头、麦克风等）
    const context = browser.defaultBrowserContext();
    await context.overridePermissions('https://shop.tiktok.com', []);
    await context.overridePermissions('https://www.tiktok.com', []);

    // 禁用页面的媒体权限请求
    await page.evaluateOnNewDocument(() => {
      // 禁用getUserMedia
      if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices.getUserMedia = () => {
          return Promise.reject(new Error('Permission denied'));
        };
      }

      // 禁用旧版本的getUserMedia
      if (navigator.getUserMedia) {
        navigator.getUserMedia = () => {
          throw new Error('Permission denied');
        };
      }

      // 禁用webkitGetUserMedia
      if (navigator.webkitGetUserMedia) {
        navigator.webkitGetUserMedia = () => {
          throw new Error('Permission denied');
        };
      }

      // 禁用mozGetUserMedia
      if (navigator.mozGetUserMedia) {
        navigator.mozGetUserMedia = () => {
          throw new Error('Permission denied');
        };
      }
    });

    // 模拟移动端的JavaScript环境
    await page.evaluateOnNewDocument(() => {
      // 移除webdriver标识
      Object.defineProperty(navigator, 'webdriver', {
        get: () => undefined,
      });

      // 模拟移动端的插件
      Object.defineProperty(navigator, 'plugins', {
        get: () => [],
      });

      // 模拟移动端平台
      Object.defineProperty(navigator, 'platform', {
        get: () => 'iPhone',
      });

      // 模拟触摸支持
      Object.defineProperty(navigator, 'maxTouchPoints', {
        get: () => 5,
      });

      // 模拟移动端的userAgent检测
      Object.defineProperty(navigator, 'userAgent', {
        get: () => 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Mobile/15E148 Safari/604.1',
      });
    });

    return page;
  }

  /**
   * 从TikTok商品链接中提取商品ID
   */
  extractProductId(url) {
    try {
      const regex = /\/product\/(\d+)/;
      const match = url.match(regex);
      return match ? match[1] : null;
    } catch (error) {
      console.error('提取商品ID失败:', error);
      return null;
    }
  }

  /**
   * 处理滑块验证
   */
  async handleSliderCaptcha(page) {
    try {
      console.log('检测到滑块验证，尝试处理...');

      // 等待滑块元素出现
      const sliderSelector = '.captcha_verify_container, .verify-slider, .slider-track, [class*="slider"], [class*="captcha"]';

      await page.waitForSelector(sliderSelector, { timeout: 5000 });
      console.log('找到滑块元素');

      // 获取滑块和轨道元素
      const slider = await page.$('.captcha_verify_container .secsdk-captcha-drag-icon, .verify-slider .slider-btn, [class*="drag"], [class*="slider-btn"]');
      const track = await page.$('.captcha_verify_container .secsdk-captcha-drag-track, .verify-slider .slider-track, [class*="track"]');

      if (slider && track) {
        // 获取滑块和轨道的位置信息
        const sliderBox = await slider.boundingBox();
        const trackBox = await track.boundingBox();

        if (sliderBox && trackBox) {
          // 计算需要滑动的距离
          const distance = trackBox.width - sliderBox.width;

          console.log(`滑块位置: ${sliderBox.x}, ${sliderBox.y}`);
          console.log(`需要滑动距离: ${distance}px`);

          // 模拟人类滑动行为
          await this.humanLikeSlide(page, slider, distance);

          // 等待验证完成
          await this.wait(2000);

          // 检查是否验证成功
          const captchaExists = await page.$('.captcha_verify_container, .verify-slider') !== null;
          if (!captchaExists) {
            console.log('滑块验证成功');
            return true;
          }
        }
      }

      console.log('滑块验证失败，尝试其他方法');
      return false;

    } catch (error) {
      console.error('处理滑块验证时出错:', error);
      return false;
    }
  }

  /**
   * 模拟人类滑动行为
   */
  async humanLikeSlide(page, slider, distance) {
    const sliderBox = await slider.boundingBox();
    const startX = sliderBox.x + sliderBox.width / 2;
    const startY = sliderBox.y + sliderBox.height / 2;

    // 移动到滑块中心
    await page.mouse.move(startX, startY);
    await this.wait(100);

    // 按下鼠标
    await page.mouse.down();
    await this.wait(100);

    // 分段滑动，模拟人类行为
    const steps = 10;
    const stepDistance = distance / steps;

    for (let i = 1; i <= steps; i++) {
      const currentX = startX + (stepDistance * i);
      const randomY = startY + (Math.random() - 0.5) * 2; // 添加轻微的Y轴抖动

      await page.mouse.move(currentX, randomY, { steps: 3 });
      await this.wait(50 + Math.random() * 50); // 随机延迟
    }

    // 释放鼠标
    await page.mouse.up();
    await this.wait(500);
  }

  /**
   * 爬取TikTok商品页面信息
   */
  async scrapeProductInfo(url) {
    let page = null;

    try {
      console.log(`开始爬取商品信息: ${url}`);

      page = await this.createPage();

      // 访问页面
      try {
        await page.goto(url, {
          waitUntil: 'domcontentloaded', // 改为更快的加载策略
          timeout: 20000 // 减少超时时间
        });
        console.log('页面加载完成');
      } catch (gotoError) {
        console.log('页面加载出现错误:', gotoError.message);

        // 检查是否是网络连接错误
        if (gotoError.message.includes('ERR_NAME_NOT_RESOLVED') ||
          gotoError.message.includes('ERR_CONNECTION_REFUSED') ||
          gotoError.message.includes('ERR_CONNECTION_TIMED_OUT') ||
          gotoError.message.includes('ERR_NETWORK_CHANGED') ||
          gotoError.message.includes('ERR_INTERNET_DISCONNECTED') ||
          gotoError.message.includes('net::ERR_') ||
          gotoError.message.includes('Navigation timeout')) {
          console.log('检测到网络连接错误，直接返回');
          return {
            title: '无法访问此网站，网络连接出现问题',
            success: false,
            error: 'NETWORK_ERROR',
            message: '无法访问此网站，网络连接出现问题',
            isPageError: true
          };
        }

        // 如果不是明确的网络错误，继续尝试处理
        console.log('尝试继续处理页面...');
      }

      // 等待页面充分加载
      console.log('等待页面内容充分加载...');
      await this.wait(6000); // 增加等待时间到6秒

      // 尝试等待关键元素出现
      const keyElementExists = await page.waitForSelector('h1, .product-title, [data-testid="pdp-product-title"], title', {
        timeout: 8000,
        visible: false // 不要求可见，只要求存在于DOM中
      }).catch(() => false);

      if (keyElementExists) {
        console.log('检测到关键元素，页面加载完成');
        // 等待页面稳定
        await this.wait(2000);
      } else {
        console.log('未检测到关键元素，但继续处理');
        // 再额外等待一段时间
        await this.wait(3000);
      }

      // 立即检测是否是错误页面
      const content = await page.content();
      const $ = cheerio.load(content);
      const pageError = this.detectPageErrors($);

      if (pageError) {
        console.log(`快速检测到页面错误，立即返回: ${pageError.type} - ${pageError.message}`);
        return {
          title: pageError.message,
          success: false,
          error: pageError.type,
          message: pageError.message,
          isPageError: true
        };
      }

      // 如果不是错误页面，继续检查验证码
      console.log('未检测到页面错误，继续处理...');

      // 检查是否有滑块验证
      const hasCaptcha = await page.$('.captcha_verify_container, .verify-slider, [class*="captcha"]') !== null;

      if (hasCaptcha) {
        console.log('检测到滑块验证');
        const captchaHandled = await this.handleSliderCaptcha(page);

        if (!captchaHandled) {
          // 不再刷新页面重试，直接返回验证码错误
          console.log('滑块验证处理失败，避免重定向不再重试');
          return {
            title: 'Captcha verification required',
            success: false,
            error: 'CAPTCHA_REQUIRED',
            message: '需要人工验证'
          };
        }

        // 验证码处理后再次检查错误页面
        const contentAfterCaptcha = await page.content();
        const $afterCaptcha = cheerio.load(contentAfterCaptcha);
        const errorAfterCaptcha = this.detectPageErrors($afterCaptcha);

        if (errorAfterCaptcha) {
          console.log(`验证码处理后检测到页面错误: ${errorAfterCaptcha.type} - ${errorAfterCaptcha.message}`);
          return {
            title: errorAfterCaptcha.message,
            success: false,
            error: errorAfterCaptcha.type,
            message: errorAfterCaptcha.message,
            isPageError: true
          };
        }
      }

      // 等待商品信息充分加载
      console.log('等待商品信息充分加载...');
      await this.wait(5000); // 增加等待时间到5秒

      // 获取页面HTML内容
      const finalContent = await page.content();
      const $final = cheerio.load(finalContent);

      // 提取商品信息
      const productInfo = await this.extractProductData($final, page);

      console.log('商品信息提取完成');
      return productInfo;

    } catch (error) {
      console.error('爬取商品信息失败:', error);
      return {
        title: '获取商品信息失败',
        success: false,
        error: error.message
      };
    } finally {
      if (page) {
        await page.close();
      }
    }
  }

  /**
   * 提取商品数据
   */
  async extractProductData($, page) {
    try {
      // 尝试从页面的JSON数据中提取信息
      const scriptTags = $('script[type="application/json"]');
      let productData = null;

      scriptTags.each((i, elem) => {
        try {
          const jsonText = $(elem).html();
          if (jsonText && jsonText.includes('product')) {
            const data = JSON.parse(jsonText);
            if (data && data.props && data.props.pageProps) {
              productData = data.props.pageProps;
            }
          }
        } catch (e) {
          // 忽略JSON解析错误
        }
      });

      // 提取基本信息
      const titleResult = this.extractTitle($, productData);

      // 检查是否是错误页面
      if (titleResult && titleResult.isError) {
        console.log(`页面错误: ${titleResult.error} - ${titleResult.message}`);
        return {
          title: titleResult.message,
          success: false,
          error: titleResult.error,
          message: titleResult.message,
          isPageError: true
        };
      }

      const title = titleResult;
      const priceInfo = this.extractPrice($, productData);
      const sellerInfo = this.extractSeller($, productData);
      const salesInfo = await this.extractSales($, page, productData);

      return {
        title: title || '未找到商品标题',
        priceUsd: priceInfo.priceUsd,
        price: priceInfo.price,
        sellerName: sellerInfo.sellerName,
        weekSoldCount: salesInfo.weekSoldCount,
        weekSales: salesInfo.weekSales,
        weekSalesUsd: salesInfo.weekSalesUsd,
        totalSales: salesInfo.totalSales,
        totalSalesUsd: salesInfo.totalSalesUsd,
        relatedVideos: salesInfo.relatedVideos,
        relatedAuthor: salesInfo.relatedAuthor,
        success: !!title
      };

    } catch (error) {
      console.error('提取商品数据失败:', error);
      return {
        title: '数据提取失败',
        success: false,
        error: error.message
      };
    }
  }

  /**
   * 检测页面错误信息
   */
  detectPageErrors($) {
    const bodyText = $('body').text();
    const titleText = $('title').text();
    const mainContent = $('main, .main-content, .content, #content').text();
    const headerText = $('h1, h2, h3').text();

    // 检测地区限制错误（优先级最高）
    if (bodyText.includes('Product not available in this country or region') ||
      bodyText.includes("This product isn't currently available in your country or region") ||
      bodyText.includes('商品在您所在的国家或地区不可用') ||
      bodyText.includes('此商品目前在您的国家或地区不可用')) {
      return {
        type: 'REGION_RESTRICTED',
        message: 'Product not available in this country or region'
      };
    }

    // 检测明确的商品不存在错误信息（更精确的检测）
    if (bodyText.includes('Product not found') ||
      bodyText.includes('Page not found') ||
      bodyText.includes('商品不存在') ||
      bodyText.includes('页面不存在') ||
      titleText.includes('404') ||
      titleText.includes('Not Found') ||
      headerText.includes('404') ||
      headerText.includes('Not Found')) {
      return {
        type: 'PRODUCT_NOT_FOUND',
        message: 'Product not found or page does not exist'
      };
    }

    // 检测404错误页面特征（更严格的检测）
    const is404Page = (
      (titleText.toLowerCase().includes('404') || titleText.toLowerCase().includes('not found')) ||
      (headerText.includes('404') && headerText.includes('not found')) ||
      (mainContent.includes('404') && mainContent.includes('page') && mainContent.includes('not found')) ||
      (bodyText.includes('404') && bodyText.includes('not found') && bodyText.length < 1000)
    );

    if (is404Page) {
      return {
        type: 'PRODUCT_NOT_FOUND',
        message: 'Product not found or page does not exist'
      };
    }

    // 检测商品已下架
    if (bodyText.includes('Product is no longer available') ||
      bodyText.includes('This product has been removed') ||
      bodyText.includes('商品已下架') ||
      bodyText.includes('商品不再可用')) {
      return {
        type: 'PRODUCT_UNAVAILABLE',
        message: 'Product is no longer available'
      };
    }

    // 检测访问被限制
    if (bodyText.includes('Access denied') ||
      bodyText.includes('Forbidden') ||
      bodyText.includes('访问被拒绝') ||
      bodyText.includes('禁止访问')) {
      return {
        type: 'ACCESS_DENIED',
        message: 'Access to this page is denied'
      };
    }

    // 检测需要登录
    if (bodyText.includes('Please log in') ||
      bodyText.includes('Sign in required') ||
      bodyText.includes('请登录') ||
      bodyText.includes('需要登录')) {
      return {
        type: 'LOGIN_REQUIRED',
        message: 'Login required to access this page'
      };
    }

    // 检测网络连接错误
    if (bodyText.includes('无法访问此网站') ||
      bodyText.includes('This site can\'t be reached') ||
      bodyText.includes('ERR_NAME_NOT_RESOLVED') ||
      bodyText.includes('ERR_CONNECTION_REFUSED') ||
      bodyText.includes('ERR_CONNECTION_TIMED_OUT') ||
      bodyText.includes('ERR_NETWORK_CHANGED') ||
      bodyText.includes('ERR_INTERNET_DISCONNECTED') ||
      bodyText.includes('Check your internet connection') ||
      bodyText.includes('检查您的互联网连接') ||
      bodyText.includes('网络连接出现问题') ||
      bodyText.includes('Connection timed out')) {
      return {
        type: 'NETWORK_ERROR',
        message: '无法访问此网站，网络连接出现问题'
      };
    }

    // 检测DNS解析错误
    if (bodyText.includes('DNS_PROBE_FINISHED_NXDOMAIN') ||
      bodyText.includes('DNS解析失败') ||
      bodyText.includes('找不到服务器') ||
      bodyText.includes('Server not found') ||
      bodyText.includes('could not be found')) {
      return {
        type: 'DNS_ERROR',
        message: 'DNS解析失败，无法找到服务器'
      };
    }

    return null;
  }

  /**
   * 提取商品标题
   */
  extractTitle($, productData) {
    // 首先检测页面是否有错误
    const pageError = this.detectPageErrors($);
    if (pageError) {
      return {
        error: pageError.type,
        message: pageError.message,
        isError: true
      };
    }

    // 优先从JSON数据中提取
    if (productData && productData.product && productData.product.title) {
      return productData.product.title;
    }

    // 从HTML中提取
    const titleSelectors = [
      'h1[data-testid="pdp-product-title"]',
      '.product-title',
      'h1.title',
      '[data-testid="product-title"]',
      'h1',
      '.pdp-product-title',
      '[class*="product-title"]',
      '[class*="title"]'
    ];

    for (const selector of titleSelectors) {
      const title = $(selector).first().text().trim();
      if (title && title.length > 5) {
        return title;
      }
    }

    // 从页面标题中提取
    const pageTitle = $('title').text().trim();
    if (pageTitle) {
      return pageTitle.replace(/\s*\|\s*TikTok Shop.*$/i, '').trim();
    }

    return null;
  }

  /**
   * 提取价格信息
   */
  extractPrice($, productData) {
    let priceUsd = null;
    let price = null;

    // 从JSON数据中提取
    if (productData && productData.product && productData.product.price) {
      const priceData = productData.product.price;
      if (priceData.current) {
        priceUsd = parseFloat(priceData.current);
      }
    }

    // 从HTML中提取
    if (!priceUsd) {
      const priceSelectors = [
        '[data-testid="pdp-price"]',
        '.price',
        '.product-price',
        '.current-price',
        '[class*="price"]'
      ];

      for (const selector of priceSelectors) {
        const priceText = $(selector).first().text().trim();
        if (priceText) {
          const priceMatch = priceText.match(/[\d,]+\.?\d*/);
          if (priceMatch) {
            const numericPrice = parseFloat(priceMatch[0].replace(/,/g, ''));

            if (priceText.includes('$') || priceText.includes('USD')) {
              priceUsd = numericPrice;
            } else if (priceText.includes('¥') || priceText.includes('RMB')) {
              price = numericPrice;
            } else {
              priceUsd = numericPrice;
            }
            break;
          }
        }
      }
    }

    return { priceUsd, price };
  }

  /**
   * 提取店铺信息
   */
  extractSeller($, productData) {
    let sellerName = null;

    // 从JSON数据中提取
    if (productData && productData.seller && productData.seller.name) {
      sellerName = productData.seller.name;
    }

    // 从HTML中提取
    if (!sellerName) {
      const sellerSelectors = [
        '[data-testid="seller-name"]',
        '.seller-name',
        '.shop-name',
        '.store-name',
        '[class*="seller"]',
        '[class*="shop"]'
      ];

      for (const selector of sellerSelectors) {
        const name = $(selector).first().text().trim();
        if (name && name.length > 1) {
          sellerName = name;
          break;
        }
      }
    }

    return { sellerName };
  }

  /**
   * 提取销售数据
   */
  async extractSales($, page, productData) {
    let weekSoldCount = null;
    let weekSales = null;
    let weekSalesUsd = null;
    let totalSales = null;
    let totalSalesUsd = null;
    let relatedVideos = null;
    let relatedAuthor = null;

    // 从JSON数据中提取
    if (productData && productData.product) {
      const product = productData.product;
      if (product.salesInfo) {
        weekSoldCount = product.salesInfo.weekSold;
        totalSales = product.salesInfo.totalSold;
      }
      if (product.videoCount) {
        relatedVideos = product.videoCount;
      }
    }

    // 从页面文本中提取
    const pageText = $('body').text();

    if (!weekSoldCount) {
      const weekSoldMatch = pageText.match(/(\d+(?:\.\d+)?[kK]?)\s*sold\s*(?:this\s*)?week/i);
      if (weekSoldMatch) {
        let count = weekSoldMatch[1].toLowerCase();
        if (count.includes('k')) {
          weekSoldCount = Math.floor(parseFloat(count.replace('k', '')) * 1000);
        } else {
          weekSoldCount = parseInt(count);
        }
      }
    }

    // 尝试从页面元素中获取更多数据
    try {
      const salesElements = await page.$$eval('[class*="sold"], [class*="sales"]', elements =>
        elements.map(el => el.textContent.trim())
      );

      for (const text of salesElements) {
        if (text.includes('sold') && !weekSoldCount) {
          const match = text.match(/(\d+(?:\.\d+)?[kK]?)/);
          if (match) {
            let count = match[1].toLowerCase();
            if (count.includes('k')) {
              weekSoldCount = Math.floor(parseFloat(count.replace('k', '')) * 1000);
            } else {
              weekSoldCount = parseInt(count);
            }
          }
        }
      }
    } catch (error) {
      console.log('提取销售数据时出错:', error.message);
    }

    return {
      weekSoldCount,
      weekSales,
      weekSalesUsd,
      totalSales,
      totalSalesUsd,
      relatedVideos,
      relatedAuthor
    };
  }

  /**
   * 关闭浏览器
   */
  async closeBrowser() {
    if (this.browser) {
      await this.browser.close();
      this.browser = null;
    }
  }
}

module.exports = new TikTokScraperAdvanced();